package com.devilwwj.http.core;

import android.webkit.URLUtil;

import com.devilwwj.http.callback.OnProgressUpdatedListener;
import com.devilwwj.http.exception.HttpException;
import com.devilwwj.http.utils.UploadUtil;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

/**
 * HttpURLConnection请求工具类
 * Created by devilwwj on 15/7/16.
 */
public class HttpURLConnectionUtil {

    private static final int READ_TIME = 5 * 1000;
    private static final int CONNECT_TIME = 5 * 1000;


    /**
     * 通用请求方法
     *
     * @param request
     * @return HttpURLConnection
     * @throws HttpException
     */
    public static HttpURLConnection execute(Request request, OnProgressUpdatedListener listener) throws HttpException {
        if (!URLUtil.isNetworkUrl(request.url)) {
            throw new HttpException(HttpException.ErrorType.MANUAL, "the url:" + request.url + "is not valid");
        }
        switch (request.method) {
            case GET:
            case DELETE:
                return get(request);
            case POST:
            case PUT:
                return post(request,listener);
            default:
                break;

        }
        return null;
    }

    /**
     * HttpURLConnection get请求方法
     *
     * @param request
     * @return HttpURLConnection
     * @throws HttpException
     */
    private static HttpURLConnection get(Request request) throws HttpException {
        try {
            request.checkIfIsCancelled();
            URL url = new URL(request.url);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            setHeaders(conn, request.headers);
            conn.setConnectTimeout(CONNECT_TIME);
            conn.setReadTimeout(READ_TIME);

            request.checkIfIsCancelled();
            return conn;
        } catch (InterruptedIOException e) {
            throw new HttpException(HttpException.ErrorType.TIMEOUT, e.getMessage());
        } catch (IOException e) {
            throw new HttpException(HttpException.ErrorType.SERVER, e.getMessage());
        }
    }

    private static HttpURLConnection post(Request request,OnProgressUpdatedListener listener) throws HttpException {
        HttpURLConnection connection = null;
        OutputStream os = null;
        try {
            request.checkIfIsCancelled();

            connection = (HttpURLConnection) new URL(request.url).openConnection();
            connection.setRequestMethod(request.method.name());
            connection.setConnectTimeout(15 * 3000);
            connection.setReadTimeout(15 * 3000);
            connection.setDoOutput(true);


            setHeaders(connection, request.headers);
            request.checkIfIsCancelled();

            os = connection.getOutputStream();
            if (request.filePath != null){
                UploadUtil.upload(os, request.filePath);
            }else if(request.fileEntities != null){
                UploadUtil.upload(os,request.content,request.fileEntities,listener);
            }else if(request.content != null){
                os.write(request.content.getBytes());
            }else {
                throw new HttpException(HttpException.ErrorType.MANUAL,"the post request has no post content");
            }

            request.checkIfIsCancelled();
        } catch (InterruptedIOException e) {
            throw new HttpException(HttpException.ErrorType.TIMEOUT, e.getMessage());
        } catch (IOException e) {
            throw new HttpException(HttpException.ErrorType.SERVER, e.getMessage());
        }finally {
            try {
                os.flush();
                os.close();
            } catch (IOException e) {
                throw new HttpException(HttpException.ErrorType.IO, "the post outputstream can't be closed");
            }
        }

        return connection;
    }

    /**
     * 设置header
     *
     * @param conn
     * @param headers
     */
    private static void setHeaders(HttpURLConnection conn, Map<String, String> headers) {
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                conn.addRequestProperty(entry.getKey(), entry.getValue());
            }
        }
    }
}
